﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data; 
using System.Text; 
using System.Windows.Forms;
using ICSharpCode.TextEditor.Document;
using ICSharpCode.TextEditor;

namespace ICSharpCode.WinFormsUI.Controls
{
    public partial class CodeFormatControl : TextBoxBase
    {
        private bool onfoused = false;      

        private Color borderColor = SystemColors.ControlDark;

        public override string Text
        {
            get
            {
                return this.textEditorControl1.Text;
            }
            set
            {
                this.textEditorControl1.Text = value;
                SetHighlightingFoldingStrategy(this.documentType);
            }
        }
        
        public CodeFormatControl()
        {
            InitializeComponent();
            InitializeControls();
        }

        protected void InitializeControls()
        {
            textEditorControl1.GotFocus += textEditorControl1_GotFocus;
            textEditorControl1.LostFocus += textEditorControl1_LostFocus;
            textEditorControl1.TextChanged+=textEditorControl1_TextChanged;
            toolStripComboBoxFontValue.SelectedIndex = 0;
            toolStripComboBoxFontSizeValue.SelectedIndex = 0;
        }

        protected void SetHighlightingFoldingStrategy(DocumentType value)
        {       
            switch (value)
            {
                case WinFormsUI.Controls.DocumentType.TSql:
                    textEditorControl1.SetHighlighting("TSQL");
                    textEditorControl1.Document.FormattingStrategy = new DefaultFormattingStrategy();
                    textEditorControl1.Document.FoldingManager.FoldingStrategy = new TsqlFoldingStrategy(); //new IndentFoldingStrategy();
                    textEditorControl1.Document.FoldingManager.UpdateFoldings();
                    break;
                case WinFormsUI.Controls.DocumentType.Csharp:
                    textEditorControl1.SetHighlighting("C#");
                    textEditorControl1.Document.FormattingStrategy = new CSharpFormattingStrategy();
                    textEditorControl1.Document.FoldingManager.FoldingStrategy = new CSharpFoldingStrategy(); //new IndentFoldingStrategy();
                    textEditorControl1.Document.FoldingManager.UpdateFoldings();
                    break;
                case WinFormsUI.Controls.DocumentType.Javascript:
                    textEditorControl1.SetHighlighting("JavaScript");
                    textEditorControl1.Document.FormattingStrategy = new CSharpFormattingStrategy();
                    textEditorControl1.Document.FoldingManager.FoldingStrategy = new CSharpFoldingStrategy(); //new IndentFoldingStrategy();
                    textEditorControl1.Document.FoldingManager.UpdateFoldings();
                    break;
                case WinFormsUI.Controls.DocumentType.Xml:
                    textEditorControl1.SetHighlighting("XML");
                    textEditorControl1.Document.FormattingStrategy = new DefaultFormattingStrategy();
                    textEditorControl1.Document.FoldingManager.FoldingStrategy = new XmlFoldingStrategy(); //new IndentFoldingStrategy();
                    textEditorControl1.Document.FoldingManager.UpdateFoldings();
                    break;
                case WinFormsUI.Controls.DocumentType.Python:
                    textEditorControl1.SetHighlighting("Python");
                    textEditorControl1.Document.FormattingStrategy = new DefaultFormattingStrategy();
                    textEditorControl1.Document.FoldingManager.FoldingStrategy = new IndentFoldingStrategy(); //new IndentFoldingStrategy();
                    textEditorControl1.Document.FoldingManager.UpdateFoldings();
                    break;
            }
        }

        protected void textEditorControl1_TextChanged(object sender, EventArgs e)
        {
            if (textEditorControl1.Document != null && textEditorControl1.Document.FoldingManager != null
                && textEditorControl1.Document.FoldingManager.FoldingStrategy != null)
                textEditorControl1.Document.FoldingManager.UpdateFoldings();
        }

        protected void textEditorControl1_GotFocus(object sender, EventArgs e)
        {
            onfoused = true;
            this.Invalidate();
        }

        protected void textEditorControl1_LostFocus(object sender, EventArgs e)
        {
            onfoused = false;
            this.Invalidate();
        }

        protected override void OnPaint(System.Windows.Forms.PaintEventArgs e)
        {
            base.OnPaint(e);

            if (onfoused)
            {
                borderColor = Color.Blue;
            }
            else
            {
                borderColor = SystemColors.ControlDark;
            }

            ControlPaint.DrawBorder(e.Graphics, this.ClientRectangle,
               borderColor, 1, ButtonBorderStyle.Solid, //左边
               borderColor, 1, ButtonBorderStyle.Solid, //上边
               borderColor, 1, ButtonBorderStyle.Solid, //右边
               borderColor, 1, ButtonBorderStyle.Solid);//底边

        }

        private void toolStripButtonLineNumber_Click(object sender, EventArgs e)
        {
            textEditorControl1.ShowLineNumbers = !textEditorControl1.ShowLineNumbers;
        }

        private void toolStripButtonAbout_Click(object sender, EventArgs e)
        {
            ShowAbout();
        }

        private void toolStripButtonAddComment_Click(object sender, EventArgs e)
        {
            TextAreaComment(1);
        }

        private void toolStripButtonRemoveComment_Click(object sender, EventArgs e)
        {
            TextAreaComment(-1);
        }

        private void toolStripComboBoxFontSizeValue_SelectedIndexChanged(object sender, EventArgs e)
        {
            var size = toolStripComboBoxFontSizeValue.SelectedItem + "";
            var font = toolStripComboBoxFontValue.SelectedItem + "";

            if (string.IsNullOrEmpty(size))
            {
                size = "9";
            }
            if (string.IsNullOrEmpty(font) || font == "默认")
            {
                font = "Courier New";
            }

            this.textEditorControl1.Font = new Font(font, float.Parse(size), FontStyle.Regular); 
        }

        private void toolStripComboBoxFontValue_SelectedIndexChanged(object sender, EventArgs e)
        {
            var size = toolStripComboBoxFontSizeValue.SelectedItem + "";
            var font = toolStripComboBoxFontValue.SelectedItem + "";

            if (string.IsNullOrEmpty(size))
            {
                size = "9";
            }
            if (string.IsNullOrEmpty(font) || font == "默认")
            {
                font = "Courier New";
            }

            this.textEditorControl1.Font = new Font(font, float.Parse(size), FontStyle.Regular); 
        }

        public override void ReleaseDispose()
        {
            base.ReleaseDispose();
        }

        public void hightStrategyChanged(object sender, EventArgs e)
        {
            string text = ((ToolStripItem)sender).Text;
            foreach (ToolStripMenuItem item in toolStripButtonLanguage.DropDownItems)
            {
                if (item.Text == text)
                {
                    item.Checked = true;
                }
                else
                {
                    item.Checked = false;
                }
            }

            var _documentType = DocumentType.None;

            switch (text)
            {
                case "Sql":
                    _documentType = DocumentType.TSql;
                    break;
                case "Javascript":
                    _documentType = DocumentType.Javascript;
                    break;
                case "Json":
                    _documentType = DocumentType.Javascript;
                    break;
                case "Python":
                    _documentType = DocumentType.Python;
                    break;
                case "Html":
                    _documentType = DocumentType.Html;
                    break;
                case "Css":
                    _documentType = DocumentType.Css;
                    break;              
                case "C#":
                    _documentType = DocumentType.Csharp;
                    break;
            }

            SetHighlightingFoldingStrategy(_documentType);

        }

        private void javascriptToolStripMenuItem_Click(object sender, EventArgs e)
        {
            hightStrategyChanged(sender, e);
        }

        private void pythonToolStripMenuItem_Click(object sender, EventArgs e)
        {
            hightStrategyChanged(sender, e);
        }

        private void cToolStripMenuItem_Click(object sender, EventArgs e)
        {
            hightStrategyChanged(sender, e);
        }

        private void cssToolStripMenuItem_Click(object sender, EventArgs e)
        {
            hightStrategyChanged(sender, e);
        }

        private void htmlToolStripMenuItem_Click(object sender, EventArgs e)
        {
            hightStrategyChanged(sender, e);
        }

        private void sqlToolStripMenuItem_Click(object sender, EventArgs e)
        {
            hightStrategyChanged(sender, e);
        }  

        private void jsonToolStripMenuItem_Click(object sender, EventArgs e)
        {
            hightStrategyChanged(sender, e);
        }

        private void toolStripButtonIndent_Click(object sender, EventArgs e)
        {
            var text = this.textEditorControl1.Text;

            TextAreaIndent(1);
        }

        private void toolStripButtonOutdent_Click(object sender, EventArgs e)
        {
            TextAreaIndent(-1);
        }

        private void toolStripButtonClear_Click(object sender, EventArgs e)
        {
            this.textEditorControl1.Text = "";
            textEditorControl1.ActiveTextAreaControl.TextArea.Invalidate();
            this.textEditorControl1.ActiveTextAreaControl.Invalidate();
        } 

        private void TextAreaIndent(int indents)
        {
            int startOffset = -1, endOffset = -1;   
            var offset = textEditorControl1.ActiveTextAreaControl.Caret.Offset;                   
            var list = textEditorControl1.ActiveTextAreaControl.SelectionManager.SelectionCollection;

            if (list.Count > 0)
            {
                foreach (var select in list)
                {
                    var start = textEditorControl1.Document.GetLineNumberForOffset(select.Offset);
                    var end = textEditorControl1.Document.GetLineNumberForOffset(select.EndOffset);
                    for (int index = start; index < end + 1; index++)
                    {
                        var line = textEditorControl1.Document.GetLineSegment(index);

                        if (line.Indent + indents >= 0 && line.Indent + indents < 100)
                        {
                            for (int i = 0; i < Math.Abs(indents); i++)
                            {
                                if (indents > 0)
                                {
                                    textEditorControl1.Document.Insert(line.Offset, "\t");
                                }
                                else
                                {
                                    textEditorControl1.Document.Remove(line.Offset, "\t".Length);
                                }
                            }                            
                        }

                        if (line.Indent + indents >= 0 && line.Indent + indents < 100)
                            line.Indent += indents;                       

                    }
                }

                startOffset = list[0].Offset;

                endOffset = list[list.Count - 1].EndOffset;

                var line3 = textEditorControl1.Document.GetLineSegmentForOffset(list[list.Count - 1].Offset);

                int d = indents;
                if (d <= 0) d += 1;

                textEditorControl1.ActiveTextAreaControl.Caret.Position = textEditorControl1.Document.OffsetToPosition(endOffset + d);

                textEditorControl1.ActiveTextAreaControl
                    .SelectionManager.SetSelection(textEditorControl1.Document.OffsetToPosition(startOffset),
                    textEditorControl1.Document.OffsetToPosition(endOffset + d));   
                 
            }
            else
            {
                var line2 = textEditorControl1.Document.GetLineSegmentForOffset(textEditorControl1.ActiveTextAreaControl.Caret.Offset);
                if (line2 != null)
                {
                    if (line2.Indent + indents >= 0 && line2.Indent + indents < 100)
                    {
                        if (indents > 0)
                        {
                            textEditorControl1.Document.Insert(line2.Offset, "\t");
                            textEditorControl1.ActiveTextAreaControl.Caret.Position = textEditorControl1.Document.OffsetToPosition(offset + "\t".Length);
                        }
                        else
                        {
                            textEditorControl1.Document.Remove(line2.Offset, "\t".Length);
                            textEditorControl1.ActiveTextAreaControl.Caret.Position = textEditorControl1.Document.OffsetToPosition(offset - "\t".Length);
                        }
                    }

                    if (line2.Indent + indents >= 0 && line2.Indent + indents < 100)
                        line2.Indent += indents;
                }
            }
           
            textEditorControl1.ActiveTextAreaControl.TextArea.Invalidate();
            textEditorControl1.ActiveTextAreaControl.Invalidate();

        }

        private void TextAreaComment(int comments)
        {
            int startOffset = -1, endOffset = -1;
            var offset = textEditorControl1.ActiveTextAreaControl.Caret.Offset;
            var list = textEditorControl1.ActiveTextAreaControl.SelectionManager.SelectionCollection;

            if (list.Count > 0)
            {
                string note = "/**/";
                foreach (var select in list)
                {
                    var start = textEditorControl1.Document.GetLineNumberForOffset(select.Offset);
                    var end = textEditorControl1.Document.GetLineNumberForOffset(select.EndOffset);

                    Caret textCaret = new Caret(textEditorControl1.ActiveTextAreaControl.TextArea);
                    textCaret.Position = select.StartPosition;

                    ///
                    ///Get Not Empty Char Column
                    ///
                    int startPox = select.StartPosition.Column;
                    for (int i = select.StartPosition.Column; i <= select.EndPosition.Column; i++)
                    {
                        textCaret.Position = new TextLocation(i, start);
                        char chr = textEditorControl1.Document.GetCharAt(textCaret.Offset);
                        if (chr != ' ')
                        {
                            startPox = i;
                            break;
                        }
                    }                   

                    for (int index = start; index < end + 1; index++)
                    {
                        var line = textEditorControl1.Document.GetLineSegment(index);

                        textCaret.Position = new TextLocation(textCaret.Column, line.LineNumber);

                        if (line.Comment + comments >= 0 && line.Comment + comments < 100)
                        {
                            for (int i = 0; i < Math.Abs(comments); i++)
                            {
                                if (comments > 0)
                                {
                                    textEditorControl1.Document.Insert(textCaret.Offset, "//");
                                }
                                else
                                {
                                    textEditorControl1.Document.Remove(textCaret.Offset, "//".Length);
                                }
                            }
                        }

                        if (line.Comment + comments >= 0 && line.Comment + comments < 100)
                            line.Comment += comments;

                    }
                }

                startOffset = list[0].Offset;

                endOffset = list[list.Count - 1].EndOffset;

                var line3 = textEditorControl1.Document.GetLineSegmentForOffset(list[list.Count - 1].Offset);

                int d = 2 * comments;
                if (d <= 0) d += 2 * (-comments);

                textEditorControl1.ActiveTextAreaControl.Caret.Position = textEditorControl1.Document.OffsetToPosition(endOffset + d);

                textEditorControl1.ActiveTextAreaControl
                    .SelectionManager.SetSelection(textEditorControl1.Document.OffsetToPosition(startOffset),
                    textEditorControl1.Document.OffsetToPosition(endOffset + d));

            }
            else
            {
                string note = "//";
                var line2 = textEditorControl1.Document.GetLineSegmentForOffset(textEditorControl1.ActiveTextAreaControl.Caret.Offset);
                if (line2 != null)
                {
                    if (line2.Comment + comments >= 0 && line2.Comment + comments < 100)
                    {
                        if (comments > 0)
                        {
                            textEditorControl1.Document.Insert(offset, "//");
                            textEditorControl1.ActiveTextAreaControl.Caret.Position = textEditorControl1.Document.OffsetToPosition(offset + "//".Length);
                        }
                        else
                        {
                            textEditorControl1.Document.Remove(offset - "//".Length, "//".Length);
                            textEditorControl1.ActiveTextAreaControl.Caret.Position = textEditorControl1.Document.OffsetToPosition(offset - "//".Length);
                        }
                    }

                    if (line2.Comment + comments >= 0 && line2.Comment + comments < 100)
                        line2.Comment += comments;
                }
            }

            textEditorControl1.ActiveTextAreaControl.TextArea.Invalidate();
            textEditorControl1.ActiveTextAreaControl.Invalidate();
        }                    

    }
}
